package cn.xzq.utils;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;


/**
 * JdbcUtils-v1.2
 * 
 * @author XC947
 *
 */
public class JdbcUtils {
	//配置文件的默认配置，要求必须把c3p0-config.xml放在src目录下
	private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
	
	//事务专用连接--单线程
	//private static Connection con = null;
	
	//事务专用连接--多线程并发
	private static ThreadLocal<Connection>  tl = new ThreadLocal<Connection>();
	/**
	 * 获取连接对象
	 * @return con
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException{
		//获取当前线程的事务专用con连接对象
		Connection con = tl.get();
		//当con不为null时，说明已经调用过beginTransacation()
		if(con != null ) return con;
		return dataSource.getConnection();
	}
	
	/**
	 * 获取连接池对象
	 * @return dataSource
	 */
	public static DataSource getDataSource(){
		return dataSource;
	}
	
	/**
	 * 开启事务
	 * 1、获取一个connection，设置它的setAutoComnmit(false)
	 * 2、保证dao中连接必须是同一个，则将connection给dao用
	 * 3、让commitTransacation与rollbackTransacation可以获取
	 * 
	 * @throws SQLException 
	 */
	public static void beginTransacation() throws SQLException{
		//获取当前线程的事务专用con连接对象
		Connection con = tl.get();
		//判读con，防止后面的代码抛出空指针异常
		if(con != null){
			throw new SQLException("事务已经开启，不必要重复开启动作！");
		}
		con = getConnection();
		con.setAutoCommit(false);
		
		tl.set(con);
	}
	
	/**
	 * 提交事务
	 * 1、获取beginTransacation提供的Connection
	 * 2、调用Connection的commit方法 
	 * 
	 * @throws SQLException 
	 */
	public static void commitTransacation() throws SQLException{
		//获取当前线程的事务专用con连接对象
		Connection con = tl.get();
		//判读con，防止后面的代码抛出空指针异常
		if(con == null){
			throw new SQLException("事务没有开启，不能提交！");
		}
		con.commit();
		con.close();
		//事务结束-con设null
		//con = null;
		tl.remove();
	}
	
	/**
	 * 事务回滚
	 * 1、获取beginTransacation提供的Connection
	 * 2、调用Connection的rollback方法 
	 * 
	 * @throws SQLException 
	 */
	public static void rollbackTransacation() throws SQLException{
		//获取当前线程的事务专用con连接对象
		Connection con = tl.get();
		//判读con，防止后面的代码抛出空指针异常
		if(con == null){
			throw new SQLException("事务没有开启，不能回滚！");
		}
		con.rollback();
		con.close();
		//事务结束-con设null
		//con = null;
		tl.remove();
	}
	
	/**
	 * 释放连接
	 * @param connection
	 * @throws SQLException 
	 */
	public static void releaseConnection(Connection connection) throws SQLException{
		/*
		 * 判断connection连接是否是事务专用，如果是，不关闭(由事务方法关闭)
		 * 如果不是，则要次方法关闭
		 */
		//获取当前线程的事务专用con连接对象
		Connection con = tl.get();
		//con == null，表示con不是事务的connection连接
		if(con == null)
			connection.close();
		/*
		 * con != null,说明有事务连接，判断参数连接是否与con相等
		 * 不等，说明参数连接不是事务连接
		 * 相等则无动作
		 */ 
		if(con != connection)
			connection.close();
	}
}
